# coding=utf-8

from typing import Dict, List
from string import Template
from generator.libsomeip.some_ip_type import Message, SomeIP, IdtItem
from utils.payload import TypeEnum

from utils.util import writeFile

from generator.libsomeip.Common import isArray, isNormal, isString, isStruct, parseType

templete_h=Template(
"""
#pragma once
#include <transfer/common.h>
#include <vsomeip/vsomeip.hpp>
#include <vector>

namespace ecarx::transfer::someip{
    
    std::vector<Signal> someipToSignals(const std::shared_ptr<vsomeip::message> response);

}
"""
)

templete_cpp=Template(
"""
#include <cstdint>
#include <memory>
#include <string.h>
#include "someip/someip_signals.h"
#include "someip/someip_structs.h"
#include "ConvertSomeIP2Signal.h"

namespace ecarx::transfer::someip{
    
    std::vector<Signal> someipToSignals(const std::shared_ptr<vsomeip::message> response){
        std::vector<Signal> signals={};
        auto methodId=response->get_method();
        vsomeip::service_t serviceid=response->get_service();
        switch((uint32_t)serviceid){
${service_id_cases}
        }
        return signals;
    }
}
"""
)

templete_service_id_case=Template(
"""
            case ${serviceId}:{
                switch(methodId){
${method_id_cases}
                }
                break;
            }"""
)

templete_method_id_case=Template(
"""
                    ${getter_id}
                    case ${method_id}:{
                        uint8_t* buffer=static_cast<uint8_t*>(response->get_payload()->get_data());
${signals}
                        break;
                    }"""
)

templete_buffer_parse=Template(
"""
                        Signal ${signalName};
                        ${signalName}.signalId=static_cast<uint32_t>(${signalId});
                        ${signalName}.mode = ${mode};
                        ${signalName}.value.${propety}={${value}};
                        signals.push_back(${signalName});"""
)

templete_buffer_uint8_array_parse=Template(
"""
                        uint32_t realLen = response->get_payload()->get_length();
                        Signal ${signalName};
                        ${signalName}.signalId=static_cast<uint32_t>(${signalId});
                        ${signalName}.mode = ${mode};
                        ${signalName}.value.bytes.reserve(realLen);
                        for(size_t i = 0;i < realLen; ++i){
                            ${signalName}.value.bytes.push_back(buffer[${offset}+i]);
                        }
                        signals.push_back(${signalName});"""
)

templete_buffer_no_impl_array_parse=Template(
"""
                        uint32_t realLen = response->get_payload()->get_length();
                        Signal ${signalName};
                        ${signalName}.signalId=static_cast<uint32_t>(${signalId});
                        ${signalName}.mode = ${mode};
                        ${signalName}.value.bytes.reserve(realLen);
                        //todo: Need to implement
                        memcpy(${signalName}.value.bytes.data(),buffer+${offset},realLen);
                        signals.push_back(${signalName});"""
)


templete_buffer_string_parse=Template(
"""
                        uint32_t realLen = response->get_payload()->get_length();
                        Signal ${signalName};
                        ${signalName}.signalId=static_cast<uint32_t>(${signalId});
                        ${signalName}.mode = ${mode};
                        ${signalName}.value.stringValue.resize(realLen,0);
                        ${signalName}.value.stringValue.assign(buffer+${offset},buffer+${offset}+realLen);
                        signals.push_back(${signalName});"""
)

templete_buffer_struct_parse=Template(
"""
                        uint32_t realLen = response->get_payload()->get_length();
                        Signal ${signalName};
                        ${signalName}.signalId=static_cast<uint32_t>(${signalId});
                        ${signalName}.mode = ${mode};
                        ${signalName}.value.bytes.resize(realLen);
                        memcpy(${signalName}.value.bytes.data(),buffer,realLen);
                        signals.push_back(${signalName});"""
)


# 0x01 0x02 0x03 0x04 0x05
# len=4 offset=1
# 
# offset+0=4 offset+1=3 offset+2=2 offset+3=1

def parse_buffer(offset,len):
    data=[]
    for i in range(len):
        if i==0:
            data.append("buffer[{}]".format(offset+i))   
        else:
            data.append("(buffer[{}] & 0xFF)<<{}".format(offset+i,i*8))
    
    return "|".join(data)

def gen_someip2SignalValue(someip:SomeIP):
    service_id_cases=[]
    method_id_cases=[]
    for msg in someip.msg:
        if msg.getterId == '0x0' and msg.eventId == '0x0':
            #no received event
            continue

        idtItemList = someip.idtItemDict.get(msg.idtName, None)
        if idtItemList is None:
            print("!!!!!! lost idtname someip2Signal:", msg.idtName)
            continue

        idtItem = idtItemList[0]
        buffer_parses=[]
        if isNormal(idtItem.idtType) == True:
            dest_type, dest_len, convert_type, c_type = parseType(idtItem.idtType)
            buffer_parses.append(templete_buffer_parse.substitute(
                signalName=msg.msgName,
                signalId="SOMEIPRX::{}EventId".format(msg.msgName),
                mode = "NotifyMode::ValueChanged",
                propety=dest_type,
                value="{}{}".format(convert_type,parse_buffer(0,dest_len))
            ))
        elif isStruct(idtItem.idtType) == True or isArray(idtItem.idtType) == True:
            # struct 和 数组 都存在 bytes 里
            buffer_parses.append(templete_buffer_struct_parse.substitute(
                signalName=msg.msgName,
                signalId="SOMEIPRX::{}EventId".format(msg.msgName),
                mode = "NotifyMode::ValueChanged",
            ))
        elif isString(idtItem.idtType) == True:
            buffer_parses.append(templete_buffer_string_parse.substitute(
                signalName=msg.msgName,
                signalId="SOMEIPRX::{}EventId".format(msg.msgName),
                mode = "NotifyMode::ValueChanged",
                offset=0
            ))

        case_getter = ""
        case_event = ""
        # if msg.getterId != '0x0':
        #     case_getter = "case " + msg.msgName + "Getter:" #存在相同的 getterid 和 eventid, 所以不支持 getterid 方法
        if msg.eventId != '0x0':
            case_event = msg.msgName + "Event"
        method_id_cases.append(templete_method_id_case.substitute(
                getter_id=case_getter,
                method_id=case_event,
                signals="".join(buffer_parses)
            ))

    service_id_cases.append(templete_service_id_case.substitute(
        serviceId="ADCU_HMI_SERVICE_ID",
        method_id_cases="".join(method_id_cases)
    ))

    writeFile("./data/transfer/libsomeip/src", "ConvertSomeIP2Signal.h",
              lambda file: file.write(templete_h.substitute()))
    writeFile("./data/transfer/libsomeip/src", "ConvertSomeIP2Signal.cpp", lambda file:
              file.write(templete_cpp.substitute(
                  service_id_cases="".join(service_id_cases)
              )))

    